Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Displaying Raw • Download


meshchatx/src/backend/docs_manager.py 22b4fcce096023ec706bab5449805e34a2912643 (22b4fcce) Text, 38.47 KB

T8b949e# SPDX-License-Identifier: 0BSD

Tff7b72import T7ee787html
Tff7b72import T7ee787io
Tff7b72import T7ee787json
Tff7b72import T7ee787logging
Tff7b72import T7ee787os
Tff7b72import T7ee787re
Tff7b72import T7ee787shutil
Tff7b72import T7ee787zipfile

Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787markdown_renderer Tff7b72import Te6edf3MarkdownRenderer

Te6edf3BUNDLED_DOCS_SUBDIR Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Ta5d6ff"Ta5d6ffreticulum-docs-bundledTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffcurrentTa5d6ff"Tb4b4b4)
Te6edf3MANIFEST_FILENAME Tff7b72= Ta5d6ff"Ta5d6ffmanifest.jsonTa5d6ff"
Te6edf3DOC_FILE_SUFFIXES Tff7b72= Tb4b4b4(Ta5d6ff"Ta5d6ff.mdTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.txtTa5d6ff"Tb4b4b4)


Tff7b72class T56d364DocsManagerTb4b4b4:
T8b949e"""Manages the bundled Reticulum manual and any user-uploaded overrides.

The Reticulum manual is shipped with the application under
<public_dir>/reticulum-docs-bundled/current. Users may upload a
replacement archive which is extracted into <storage_dir>/reticulum-docs
and takes precedence at request time. Removing the user upload restores the
bundled copy. There is no runtime download path. Fresh manuals are staged at
build time with scripts/build/fetch_reticulum_manual.py (pnpm run build-docs).
"""

Tff7b72def Tff7b72__init__Tb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3configTb4b4b4,
Te6edf3public_dirTb4b4b4,
Te6edf3project_rootTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3storage_dirTff7b72=Tff7b72NoneTb4b4b4,
Tff7b72*Tb4b4b4,
Te6edf3populateTb4b4b4: Tffa657bool Tff7b72= Tff7b72TrueTb4b4b4,
Tb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffconfig Tff7b72= Te6edf3config
Tff7b72selfTff7b72.Td2a8ffpublic_dir Tff7b72= Te6edf3public_dir
Tff7b72selfTff7b72.Td2a8ffproject_root Tff7b72= Te6edf3project_root
Tff7b72selfTff7b72.Td2a8ffstorage_dir Tff7b72= Te6edf3storage_dir

Tff7b72if Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffdocs_base_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4, Ta5d6ff"Ta5d6ffreticulum-docsTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4, Ta5d6ff"Ta5d6ffmeshchatx-docsTa5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffdocs_base_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpublic_dirTb4b4b4, Ta5d6ff"Ta5d6ffreticulum-docsTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpublic_dirTb4b4b4, Ta5d6ff"Ta5d6ffmeshchatx-docsTa5d6ff"Tb4b4b4)

Tff7b72selfTff7b72.Td2a8ffdocs_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_base_dirTb4b4b4, Ta5d6ff"Ta5d6ffcurrentTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffversions_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_base_dirTb4b4b4, Ta5d6ff"Ta5d6ffversionsTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffbundled_docs_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpublic_dirTb4b4b4, Te6edf3BUNDLED_DOCS_SUBDIRTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffupload_status Tff7b72= Ta5d6ff"Ta5d6ffidleTa5d6ff"
Tff7b72selfTff7b72.Td2a8ffupload_progress Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8fflast_error Tff7b72= Tff7b72None

Tff7b72tryTb4b4b4:
Tff7b72for Te6edf3d Tff7b72in Tb4b4b4[
Tff7b72selfTff7b72.Td2a8ffdocs_base_dirTb4b4b4,
Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4,
Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4,
Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4,
Tb4b4b4]Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3dTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3dTb4b4b4)

Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4) Tff7b72or Tff7b72not Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_update_current_linkTb4b4b4(Tb4b4b4)

Tff7b72except Tf85149OSError Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to create documentation directories: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8fflast_error Tff7b72= Tffa657strTb4b4b4(Te6edf3eTb4b4b4)

Tff7b72if Te6edf3populateTb4b4b4:
Tff7b72selfTff7b72.Td2a8ffensure_meshchatx_docs_populatedTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffensure_meshchatx_docs_populatedTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Copy/render MeshChatX docs into storage when writable."""
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4) Tff7b72and Te6edf3osTff7b72.Td2a8ffaccessTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4,
Te6edf3osTff7b72.Td2a8ffW_OKTb4b4b4,
Tb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffpopulate_meshchatx_docsTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ff_update_current_linkTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3versionTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
T8b949e"""Update the 'current' directory to point at the chosen or latest version."""
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4)Tb4b4b4:
Tff7b72return

Te6edf3versions Tff7b72= Tff7b72selfTff7b72.Td2a8ffget_available_versionsTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3versionsTb4b4b4:
Tff7b72return

Te6edf3target_version Tff7b72= Te6edf3version Tff7b72or Te6edf3versionsTb4b4b4[Tff7b72-T79c0ff1Tb4b4b4]

Te6edf3version_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4, Te6edf3target_versionTb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3version_pathTb4b4b4)Tb4b4b4:
Tff7b72return

Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffislinkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffunlinkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_remove_tree_force_writableTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)

Tff7b72tryTb4b4b4:
Te6edf3rel_target Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrelpathTb4b4b4(Te6edf3version_pathTb4b4b4, Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffdirnameTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffsymlinkTb4b4b4(Te6edf3rel_targetTb4b4b4, Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)
Tff7b72except Tb4b4b4(Tf85149OSErrorTb4b4b4, Tf85149AttributeErrorTb4b4b4)Tb4b4b4:
Te6edf3shutilTff7b72.Td2a8ffcopytreeTb4b4b4(Te6edf3version_pathTb4b4b4, Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)

Tff7b72def Td2a8ffget_available_versionsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]
Te6edf3versions Tff7b72= Tb4b4b4[
Te6edf3d
Tff7b72for Te6edf3d Tff7b72in Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4, Te6edf3dTb4b4b4)Tb4b4b4)
Tb4b4b4]
Tff7b72return Tffa657sortedTb4b4b4(Te6edf3versionsTb4b4b4)

Tff7b72def Td2a8ffget_current_versionTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None

Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffislinkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3osTff7b72.Td2a8ffreadlinkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)Tb4b4b4)

Te6edf3version_file Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4, Ta5d6ff"Ta5d6ff.versionTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3version_fileTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3version_fileTb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Tff7b72return Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149OSErrorTb4b4b4:
Tff7b72pass

Tff7b72if Tff7b72selfTff7b72.Td2a8ffhas_user_docsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ffunknownTa5d6ff"
Tff7b72if Tff7b72selfTff7b72.Td2a8ffhas_bundled_docsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ffbundledTa5d6ff"
Tff7b72return Tff7b72None

Tff7b72def Td2a8ffswitch_versionTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3versionTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3version Tff7b72in Tff7b72selfTff7b72.Td2a8ffget_available_versionsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_update_current_linkTb4b4b4(Te6edf3versionTb4b4b4)
Tff7b72return Tff7b72True
Tff7b72return Tff7b72False

Tff7b72def Td2a8ffdelete_versionTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3versionTb4b4b4)Tb4b4b4:
T8b949e"""Delete a specific user-uploaded version of the documentation."""
Tff7b72if Te6edf3version Tff7b72not Tff7b72in Tff7b72selfTff7b72.Td2a8ffget_available_versionsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False

Te6edf3version_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4, Te6edf3versionTb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3version_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False

Tff7b72tryTb4b4b4:
Te6edf3current_version Tff7b72= Tff7b72selfTff7b72.Td2a8ffget_current_versionTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3current_version Tff7b72== Te6edf3versionTb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffislinkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffunlinkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_remove_tree_force_writableTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4)

Tff7b72selfTff7b72.Td2a8ff_remove_tree_force_writableTb4b4b4(Te6edf3version_pathTb4b4b4)

Tff7b72if Te6edf3current_version Tff7b72== Te6edf3versionTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_update_current_linkTb4b4b4(Tb4b4b4)

Tff7b72return Tff7b72True
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to delete docs version Tffd700{Te6edf3versionTffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72False

Tff7b72def Td2a8ffclear_reticulum_docsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Remove every user-uploaded Reticulum doc; bundled copy is untouched."""
Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_base_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3item Tff7b72in Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_base_dirTb4b4b4)Tb4b4b4:
Te6edf3item_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_base_dirTb4b4b4, Te6edf3itemTb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffislinkTb4b4b4(Te6edf3item_pathTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffunlinkTb4b4b4(Te6edf3item_pathTb4b4b4)
Tff7b72elif Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3item_pathTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_remove_tree_force_writableTb4b4b4(Te6edf3item_pathTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3item_pathTb4b4b4)

Tff7b72for Te6edf3d Tff7b72in Tb4b4b4[Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4, Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4]Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3dTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3dTb4b4b4)
Tff7b72return Tff7b72True
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to clear Reticulum docs: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72False

Tff7b72def Td2a8ffpopulate_meshchatx_docsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Copy the project's bundled MeshChatX markdown docs into storage."""
Te6edf3search_paths Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72if Tff7b72selfTff7b72.Td2a8ffproject_rootTb4b4b4:
Te6edf3search_pathsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffproject_rootTb4b4b4, Ta5d6ff"Ta5d6ffdocsTa5d6ff"Tb4b4b4)Tb4b4b4)

Te6edf3search_pathsTff7b72.Td2a8ffappendTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffpublic_dirTb4b4b4, Ta5d6ff"Ta5d6ffmeshchatx-docsTa5d6ff"Tb4b4b4)Tb4b4b4)

Te6edf3this_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffdirnameTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffabspathTb4b4b4(Tff7b72__file__Tb4b4b4)Tb4b4b4)
Te6edf3search_pathsTff7b72.Td2a8ffappendTb4b4b4(
Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffabspathTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3this_dirTb4b4b4, Ta5d6ff"Ta5d6ff..Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff..Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff..Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffdocsTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Te6edf3candidate_dirs Tff7b72= Tb4b4b4[Te6edf3p Tff7b72for Te6edf3p Tff7b72in Te6edf3search_paths Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3pTb4b4b4)Tb4b4b4]
Tff7b72if Tff7b72not Te6edf3candidate_dirsTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff"Ta5d6ffMeshChatX docs source directory not found.Ta5d6ff"Tb4b4b4)
Tff7b72return

Te6edf3src_docs Tff7b72= Te6edf3candidate_dirsTb4b4b4[T79c0ff0Tb4b4b4]
Tff7b72for Te6edf3base Tff7b72in Te6edf3candidate_dirsTb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3baseTb4b4b4, Te6edf3MANIFEST_FILENAMETb4b4b4)Tb4b4b4)Tb4b4b4:
Te6edf3src_docs Tff7b72= Te6edf3base
Tff7b72break

Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffaccessTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4, Te6edf3osTff7b72.Td2a8ffW_OKTb4b4b4)Tb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff"Ta5d6ffMeshChatX docs directory is not writable.Ta5d6ff"Tb4b4b4)
Tff7b72return

Tff7b72tryTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_sync_docs_treeTb4b4b4(Te6edf3src_docsTb4b4b4, Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_render_meshchatx_html_exportsTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to populate MeshChatX docs: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)

Tff7b72def Td2a8ff_sync_docs_treeTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3src_docsTb4b4b4, Te6edf3dest_dirTb4b4b4)Tb4b4b4:
T8b949e"""Copy manifest, markdown, and text files from src_docs into dest_dir.

Skips agents/ (contributor and automated-agent guidance, not
end-user documentation).
"""
Tff7b72for Te6edf3rootTb4b4b4, Te6edf3dirnamesTb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Te6edf3src_docsTb4b4b4)Tb4b4b4:
Te6edf3rel_root Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrelpathTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3src_docsTb4b4b4)
Tff7b72if Te6edf3rel_root Tff7b72== Ta5d6ff"Ta5d6ff.Ta5d6ff"Tb4b4b4:
Te6edf3dirnamesTb4b4b4[Tb4b4b4:Tb4b4b4] Tff7b72= Tb4b4b4[Te6edf3d Tff7b72for Te6edf3d Tff7b72in Te6edf3dirnames Tff7b72if Te6edf3d Tff7b72!= Ta5d6ff"Ta5d6ffagentsTa5d6ff"Tb4b4b4]
Tff7b72elif Te6edf3rel_root Tff7b72== Ta5d6ff"Ta5d6ffagentsTa5d6ff" Tff7b72or Te6edf3rel_rootTff7b72.Td2a8ffstartswithTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffagentsTffd700{Te6edf3osTff7b72.Td2a8ffsepTffd700}Ta5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3dirnamesTb4b4b4[Tb4b4b4:Tb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72continue
Te6edf3target_root Tff7b72= Tb4b4b4(
Te6edf3dest_dir Tff7b72if Te6edf3rel_root Tff7b72== Ta5d6ff"Ta5d6ff.Ta5d6ff" Tff7b72else Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3dest_dirTb4b4b4, Te6edf3rel_rootTb4b4b4)
Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3target_rootTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72for Te6edf3file Tff7b72in Te6edf3filesTb4b4b4:
Tff7b72if Te6edf3file Tff7b72== Te6edf3MANIFEST_FILENAME Tff7b72or Te6edf3fileTff7b72.Td2a8ffendswithTb4b4b4(Te6edf3DOC_FILE_SUFFIXESTb4b4b4)Tb4b4b4:
Te6edf3src_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3fileTb4b4b4)
Te6edf3dest_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3target_rootTb4b4b4, Te6edf3fileTb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffabspathTb4b4b4(Te6edf3src_pathTb4b4b4) Tff7b72!= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffabspathTb4b4b4(Te6edf3dest_pathTb4b4b4)Tb4b4b4:
Te6edf3shutilTff7b72.Td2a8ffcopy2Tb4b4b4(Te6edf3src_pathTb4b4b4, Te6edf3dest_pathTb4b4b4)

Tff7b72def Td2a8ff_render_meshchatx_html_exportsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3index_linksTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3manifestTb4b4b4, Te6edf3_manifest_error Tff7b72= Tff7b72selfTff7b72.Td2a8ff_read_manifestTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3manifest Tff7b72and Te6edf3manifestTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffsectionsTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3section Tff7b72in Tffa657sortedTb4b4b4(
Te6edf3manifestTb4b4b4[Ta5d6ff"Ta5d6ffsectionsTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3keyTff7b72=Tff7b72lambda Te6edf3sTb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fforderTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3section_title Tff7b72= Tff7b72selfTff7b72.Td2a8ff_localized_textTb4b4b4(
Te6edf3sectionTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3manifestTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdefault_languageTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3section_titleTb4b4b4:
Te6edf3index_linksTff7b72.Td2a8ffappendTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffmb-1 text-sm font-bold text-zinc-300 mt-4Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3section_titleTb4b4b4)Tffd700}Ta5d6ff</li>Ta5d6ff'Tb4b4b4,
Tb4b4b4)
Tff7b72for Te6edf3item Tff7b72in Te6edf3sectionTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffitemsTa5d6ff"Tb4b4b4, Tb4b4b4[Tb4b4b4]Tb4b4b4)Tb4b4b4:
Te6edf3rel_path Tff7b72= Te6edf3itemTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3rel_path Tff7b72or Tff7b72not Te6edf3rel_pathTff7b72.Td2a8ffendswithTb4b4b4(Te6edf3DOC_FILE_SUFFIXESTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3title Tff7b72= Tff7b72selfTff7b72.Td2a8ff_localized_textTb4b4b4(
Te6edf3itemTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3itemTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflangTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3manifestTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdefault_languageTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3html_file Tff7b72= Tff7b72selfTff7b72.Td2a8ff_doc_html_nameTb4b4b4(Te6edf3rel_pathTb4b4b4)
Tff7b72if Te6edf3titleTb4b4b4:
Te6edf3index_linksTff7b72.Td2a8ffappendTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffmb-2 ml-3Ta5d6ff"Ta5d6ff><a href=Ta5d6ff"Tffd700{Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3html_fileTb4b4b4)Tffd700}Ta5d6ff"Ta5d6ff class=Ta5d6ff"Ta5d6fftext-blue-400 hover:text-blue-300Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3titleTb4b4b4)Tffd700}Ta5d6ff</a></li>Ta5d6ff'Tb4b4b4,
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_write_doc_html_exportTb4b4b4(Te6edf3rel_pathTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72for Te6edf3doc Tff7b72in Tff7b72selfTff7b72.Td2a8ff_collect_flat_docsTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3rel_path Tff7b72= Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4]
Te6edf3html_file Tff7b72= Tff7b72selfTff7b72.Td2a8ff_write_doc_html_exportTb4b4b4(Te6edf3rel_pathTb4b4b4)
Tff7b72if Te6edf3html_fileTb4b4b4:
Te6edf3label Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3rel_pathTb4b4b4)
Te6edf3index_linksTff7b72.Td2a8ffappendTb4b4b4(
Ta5d6fffTa5d6ff'Ta5d6ff<li class=Ta5d6ff"Ta5d6ffmb-2Ta5d6ff"Ta5d6ff><a href=Ta5d6ff"Tffd700{Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3html_fileTb4b4b4)Tffd700}Ta5d6ff"Ta5d6ff class=Ta5d6ff"Ta5d6fftext-blue-400 hover:text-blue-300Ta5d6ff"Ta5d6ff>Tffd700{Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3labelTb4b4b4)Tffd700}Ta5d6ff</a></li>Ta5d6ff'Tb4b4b4,
Tb4b4b4)

Tff7b72if Te6edf3index_linksTb4b4b4:
Te6edf3index_html Tff7b72= Tff7b72selfTff7b72.Td2a8ff_standalone_html_shellTb4b4b4(
Ta5d6ff"Ta5d6ffMeshChatX DocumentationTa5d6ff"Tb4b4b4,
Ta5d6fffTa5d6ff'Ta5d6ff<h1 class=Ta5d6ff"Ta5d6fftext-2xl font-bold mb-4Ta5d6ff"Ta5d6ff>MeshChatX Documentation</h1><ul class=Ta5d6ff"Ta5d6fflist-none pl-0Ta5d6ff"Ta5d6ff>Tffd700{Ta5d6ff"Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3index_linksTb4b4b4)Tffd700}Ta5d6ff</ul>Ta5d6ff'Tb4b4b4,
Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(
Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4, Ta5d6ff"Ta5d6ffindex.htmlTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4,
Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4,
Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3index_htmlTb4b4b4)

Tff7b72def Td2a8ff_write_doc_html_exportTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3rel_pathTb4b4b4)Tb4b4b4:
Te6edf3full_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4, Te6edf3rel_pathTb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3full_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3full_pathTb4b4b4, Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3content Tff7b72= Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3rel_pathTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.mdTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3body Tff7b72= Te6edf3MarkdownRendererTff7b72.Td2a8ffrenderTb4b4b4(Te6edf3contentTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3body Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ff<pre class=Ta5d6ff'Ta5d6ffwhitespace-pre-wrap font-monoTa5d6ff'Ta5d6ff>Tffd700{Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3contentTb4b4b4)Tffd700}Ta5d6ff</pre>Ta5d6ff"
Te6edf3title Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3rel_pathTb4b4b4)
Te6edf3html_file Tff7b72= Tff7b72selfTff7b72.Td2a8ff_doc_html_nameTb4b4b4(Te6edf3rel_pathTb4b4b4)
Te6edf3html_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4, Te6edf3html_fileTb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffdirnameTb4b4b4(Te6edf3html_pathTb4b4b4)Tb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Te6edf3doc_html Tff7b72= Tff7b72selfTff7b72.Td2a8ff_standalone_html_shellTb4b4b4(
Te6edf3titleTb4b4b4,
Ta5d6fffTa5d6ff'Ta5d6ff<div class=Ta5d6ff"Ta5d6ffmax-w-none break-wordsTa5d6ff"Ta5d6ff>Tffd700{Te6edf3bodyTffd700}Ta5d6ff</div>Ta5d6ff'Tb4b4b4,
Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3html_pathTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4, Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3doc_htmlTb4b4b4)
Tff7b72return Te6edf3html_file
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to render Tffd700{Te6edf3rel_pathTffd700}Ta5d6ff to HTML: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72None

Tf0883e@staticmethod
Tff7b72def Td2a8ff_doc_html_nameTb4b4b4(Te6edf3rel_pathTb4b4b4)Tb4b4b4:
Te6edf3baseTb4b4b4, Te6edf3_ext Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffsplitextTb4b4b4(Te6edf3rel_pathTb4b4b4)
Tff7b72return Ta5d6fffTa5d6ff"Tffd700{Te6edf3baseTffd700}Ta5d6ff.htmlTa5d6ff"

Tf0883e@staticmethod
Tff7b72def Td2a8ff_standalone_html_shellTb4b4b4(Te6edf3titleTb4b4b4, Te6edf3body_htmlTb4b4b4)Tb4b4b4:
Te6edf3safe_title Tff7b72= Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3titleTb4b4b4)
Tff7b72return Ta5d6fffTa5d6ff"""Ta5d6ff<!DOCTYPE html>
Ta5d6ff<html lang=Ta5d6ff"Ta5d6ffenTa5d6ff"Ta5d6ff>
Ta5d6ff<head>
Ta5d6ff <meta charset=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Ta5d6ff>
Ta5d6ff <meta name=Ta5d6ff"Ta5d6ffviewportTa5d6ff"Ta5d6ff content=Ta5d6ff"Ta5d6ffwidth=device-width, initial-scale=1Ta5d6ff"Ta5d6ff>
Ta5d6ff <meta name=Ta5d6ff"Ta5d6ffcolor-schemeTa5d6ff"Ta5d6ff content=Ta5d6ff"Ta5d6fflight darkTa5d6ff"Ta5d6ff>
Ta5d6ff <title>Tffd700{Te6edf3safe_titleTffd700}Ta5d6ff</title>
Ta5d6ff <script src=Ta5d6ff"Ta5d6ff/assets/js/tailwindcss/tailwind-v3.4.3-forms-v0.5.7.jsTa5d6ff"Ta5d6ff></script>
Ta5d6ff <style>
Ta5d6ff :root Tffea00{{
Ta5d6ff color-scheme: light dark;
Ta5d6ff --mc-bg: #f8fafc;
Ta5d6ff --mc-fg: #111827;
Ta5d6ff --mc-muted: #6b7280;
Ta5d6ff --mc-code-bg: #1e293b;
Ta5d6ff --mc-code-fg: #f1f5f9;
Ta5d6ff --mc-border: #e5e7eb;
Ta5d6ff Tffea00}}
Ta5d6ff @media (prefers-color-scheme: dark) Tffea00{{
Ta5d6ff :root Tffea00{{
Ta5d6ff --mc-bg: #09090b;
Ta5d6ff --mc-fg: #f4f4f5;
Ta5d6ff --mc-muted: #a1a1aa;
Ta5d6ff --mc-code-bg: #18181b;
Ta5d6ff --mc-code-fg: #f4f4f5;
Ta5d6ff --mc-border: #3f3f46;
Ta5d6ff Tffea00}}
Ta5d6ff Tffea00}}
Ta5d6ff body Tffea00{{
Ta5d6ff background-color: var(--mc-bg);
Ta5d6ff color: var(--mc-fg);
Ta5d6ff Tffea00}}
Ta5d6ff a Tffea00{{Ta5d6ff color: #2563eb; Tffea00}}
Ta5d6ff @media (prefers-color-scheme: dark) Tffea00{{
Ta5d6ff a Tffea00{{Ta5d6ff color: #60a5fa; Tffea00}}
Ta5d6ff Tffea00}}
Ta5d6ff pre, code Tffea00{{
Ta5d6ff background-color: var(--mc-code-bg);
Ta5d6ff color: var(--mc-code-fg);
Ta5d6ff Tffea00}}
Ta5d6ff th, td Tffea00{{Ta5d6ff border-color: var(--mc-border); Tffea00}}
Ta5d6ff </style>
Ta5d6ff</head>
Ta5d6ff<body class=Ta5d6ff"Ta5d6ffp-4 md:p-8 max-w-4xl mx-autoTa5d6ff"Ta5d6ff>
Ta5d6ff Tffd700{Te6edf3body_htmlTffd700}
Ta5d6ff</body>
Ta5d6ff</html>Ta5d6ff"""

Tff7b72def Td2a8ffget_statusTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffupload_statusTb4b4b4,
Ta5d6ff"Ta5d6ffprogressTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffupload_progressTb4b4b4,
Ta5d6ff"Ta5d6fflast_errorTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8fflast_errorTb4b4b4,
Ta5d6ff"Ta5d6ffhas_docsTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffhas_docsTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffhas_bundled_docsTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffhas_bundled_docsTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffhas_user_docsTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffhas_user_docsTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffhas_meshchatx_docsTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffhas_meshchatx_docsTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffversionsTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffget_available_versionsTb4b4b4(Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffcurrent_versionTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ffget_current_versionTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}

Tff7b72def Td2a8ffhas_meshchatx_docsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Tff7b72return Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ff_collect_flat_docsTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72> T79c0ff0

Tff7b72def Td2a8ffget_meshchatx_docs_listTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3langTff7b72=Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3manifestTb4b4b4, Te6edf3manifest_error Tff7b72= Tff7b72selfTff7b72.Td2a8ff_read_manifestTb4b4b4(Tb4b4b4)
Te6edf3flat_docs Tff7b72= Tff7b72selfTff7b72.Td2a8ff_collect_flat_docsTb4b4b4(Tb4b4b4)
Te6edf3languages Tff7b72= Te6edf3manifestTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflanguagesTa5d6ff"Tb4b4b4) Tff7b72if Te6edf3manifest Tff7b72else Tff7b72None
Tff7b72if Tff7b72not Te6edf3languagesTb4b4b4:
Te6edf3languages Tff7b72= Tb4b4b4[Tb4b4b4{Ta5d6ff"Ta5d6ffcodeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffEnglishTa5d6ff"Tb4b4b4}Tb4b4b4]
Te6edf3default_language Tff7b72= Te6edf3manifestTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdefault_languageTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4) Tff7b72if Te6edf3manifest Tff7b72else Ta5d6ff"Ta5d6ffenTa5d6ff"
Te6edf3sections Tff7b72= Tff7b72selfTff7b72.Td2a8ff_build_sectionsTb4b4b4(Te6edf3manifestTb4b4b4, Te6edf3langTb4b4b4, Te6edf3default_languageTb4b4b4, Te6edf3flat_docsTb4b4b4)
Te6edf3result Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffdocsTa5d6ff"Tb4b4b4: Te6edf3flat_docsTb4b4b4,
Ta5d6ff"Ta5d6ffsectionsTa5d6ff"Tb4b4b4: Te6edf3sectionsTb4b4b4,
Ta5d6ff"Ta5d6fflanguagesTa5d6ff"Tb4b4b4: Te6edf3languagesTb4b4b4,
Ta5d6ff"Ta5d6ffdefault_languageTa5d6ff"Tb4b4b4: Te6edf3default_languageTb4b4b4,
Tb4b4b4}
Tff7b72if Te6edf3manifest_errorTb4b4b4:
Te6edf3resultTb4b4b4[Ta5d6ff"Ta5d6ffmanifest_errorTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3manifest_error
Tff7b72return Te6edf3result

Tf0883e@staticmethod
Tff7b72def Td2a8ff_is_safe_doc_pathTb4b4b4(Te6edf3pathTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3path Tff7b72or Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3pathTb4b4b4, Tffa657strTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Tff7b72if Ta5d6ff"Tffea00\0Ta5d6ff" Tff7b72in Te6edf3pathTb4b4b4:
Tff7b72return Tff7b72False
Te6edf3normalized Tff7b72= Te6edf3pathTff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Tffea00\\Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3normalized Tff7b72or Te6edf3normalizedTff7b72.Td2a8ffstartswithTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72False
Te6edf3parts Tff7b72= Tb4b4b4[Te6edf3part Tff7b72for Te6edf3part Tff7b72in Te6edf3normalizedTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4) Tff7b72if Te6edf3part Tff7b72not Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.Ta5d6ff"Tb4b4b4)Tb4b4b4]
Tff7b72return Ta5d6ff"Ta5d6ff..Ta5d6ff" Tff7b72not Tff7b72in Te6edf3parts

Tff7b72def Td2a8ff_read_manifestTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3manifest_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4, Te6edf3MANIFEST_FILENAMETb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3manifest_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72NoneTb4b4b4, Tff7b72None
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3manifest_pathTb4b4b4, Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3data Tff7b72= Te6edf3jsonTff7b72.Td2a8ffloadTb4b4b4(Te6edf3fTb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3dataTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72NoneTb4b4b4, Ta5d6ff"Ta5d6ffManifest must be a JSON objectTa5d6ff"
Tff7b72return Te6edf3dataTb4b4b4, Tff7b72None
Tff7b72except Te6edf3jsonTff7b72.Td2a8ffJSONDecodeError Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to parse docs manifest: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72NoneTb4b4b4, Ta5d6ff"Ta5d6ffInvalid manifest JSONTa5d6ff"
Tff7b72except Tf85149OSError Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to read docs manifest: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72NoneTb4b4b4, Ta5d6ff"Ta5d6ffCould not read manifest fileTa5d6ff"

Tff7b72def Td2a8ff_collect_flat_docsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3docs Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3docs

Tff7b72for Te6edf3rootTb4b4b4, Te6edf3_Tb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3file Tff7b72in Te6edf3filesTb4b4b4:
Tff7b72if Tff7b72not Te6edf3fileTff7b72.Td2a8ffendswithTb4b4b4(Te6edf3DOC_FILE_SUFFIXESTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3file_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3fileTb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3rel_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrelpathTb4b4b4(Te6edf3file_pathTb4b4b4, Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)
Tff7b72except Tf85149ValueErrorTb4b4b4:
Tff7b72continue
Te6edf3rel_path Tff7b72= Te6edf3rel_pathTff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Tffea00\\Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)
Te6edf3docsTff7b72.Td2a8ffappendTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Te6edf3fileTb4b4b4,
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3rel_pathTb4b4b4,
Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmarkdownTa5d6ff" Tff7b72if Te6edf3fileTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.mdTa5d6ff"Tb4b4b4) Tff7b72else Ta5d6ff"Ta5d6fftextTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72return Tffa657sortedTb4b4b4(Te6edf3docsTb4b4b4, Te6edf3keyTff7b72=Tff7b72lambda Te6edf3xTb4b4b4: Te6edf3xTb4b4b4[Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4]Tb4b4b4)

Tff7b72def Td2a8ff_build_sectionsTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3manifestTb4b4b4, Te6edf3langTb4b4b4, Te6edf3default_languageTb4b4b4, Te6edf3flat_docsTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3manifest Tff7b72or Tff7b72not Te6edf3manifestTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffsectionsTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[
Tb4b4b4{
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffallTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ff_localized_textTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffGuidesTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3langTb4b4b4,
Te6edf3default_languageTb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffitemsTa5d6ff"Tb4b4b4: Tb4b4b4[
Tb4b4b4{
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4]Tb4b4b4,
Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ff_title_from_pathTb4b4b4(Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4]Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fflangTa5d6ff"Tb4b4b4: Te6edf3default_languageTb4b4b4,
Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4: Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4}
Tff7b72for Te6edf3doc Tff7b72in Te6edf3flat_docs
Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4]

Te6edf3available Tff7b72= Tb4b4b4{Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4] Tff7b72for Te6edf3doc Tff7b72in Te6edf3flat_docsTb4b4b4}
Te6edf3sections Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3section Tff7b72in Tffa657sortedTb4b4b4(
Te6edf3manifestTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffsectionsTa5d6ff"Tb4b4b4, Tb4b4b4[Tb4b4b4]Tb4b4b4)Tb4b4b4,
Te6edf3keyTff7b72=Tff7b72lambda Te6edf3sTb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fforderTa5d6ff"Tb4b4b4, T79c0ff0Tb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3items Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3item Tff7b72in Te6edf3sectionTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffitemsTa5d6ff"Tb4b4b4, Tb4b4b4[Tb4b4b4]Tb4b4b4)Tb4b4b4:
Te6edf3rel_path Tff7b72= Te6edf3itemTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3rel_path Tff7b72or Te6edf3rel_path Tff7b72not Tff7b72in Te6edf3availableTb4b4b4:
Tff7b72continue
Te6edf3item_lang Tff7b72= Te6edf3itemTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflangTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3default_language
Te6edf3doc_type Tff7b72= Ta5d6ff"Ta5d6ffmarkdownTa5d6ff" Tff7b72if Te6edf3rel_pathTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.mdTa5d6ff"Tb4b4b4) Tff7b72else Ta5d6ff"Ta5d6fftextTa5d6ff"
Te6edf3itemsTff7b72.Td2a8ffappendTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3rel_pathTb4b4b4,
Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ff_localized_textTb4b4b4(
Te6edf3itemTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3langTb4b4b4,
Te6edf3item_lang Tff7b72or Te6edf3default_languageTb4b4b4,
Tb4b4b4)
Tff7b72or Tff7b72selfTff7b72.Td2a8ff_title_from_pathTb4b4b4(Te6edf3rel_pathTb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fflangTa5d6ff"Tb4b4b4: Te6edf3item_langTb4b4b4,
Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4: Te6edf3doc_typeTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3itemsTb4b4b4:
Te6edf3sectionsTff7b72.Td2a8ffappendTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3sectionTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3sectionTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffsectionTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4: Tff7b72selfTff7b72.Td2a8ff_localized_textTb4b4b4(
Te6edf3sectionTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4)Tb4b4b4,
Te6edf3langTb4b4b4,
Te6edf3default_languageTb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffitemsTa5d6ff"Tb4b4b4: Te6edf3itemsTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3sections

Tf0883e@staticmethod
Tff7b72def Td2a8ff_localized_textTb4b4b4(Te6edf3valueTb4b4b4, Te6edf3langTb4b4b4, Te6edf3fallbackTff7b72=Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3value Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Ta5d6ff"Ta5d6ff"
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3valueTb4b4b4, Tffa657strTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3value
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3valueTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4(
Te6edf3valueTff7b72.Td2a8ffgetTb4b4b4(Te6edf3langTb4b4b4) Tff7b72or Te6edf3valueTff7b72.Td2a8ffgetTb4b4b4(Te6edf3fallbackTb4b4b4) Tff7b72or Tffa657nextTb4b4b4(Tffa657iterTb4b4b4(Te6edf3valueTff7b72.Td2a8ffvaluesTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
Tb4b4b4)
Tff7b72return Tffa657strTb4b4b4(Te6edf3valueTb4b4b4)

Tf0883e@staticmethod
Tff7b72def Td2a8ff_title_from_pathTb4b4b4(Te6edf3rel_pathTb4b4b4)Tb4b4b4:
Te6edf3base Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3rel_pathTb4b4b4)
Tff7b72return Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffsplitextTb4b4b4(Te6edf3baseTb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4]Tff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Ta5d6ff-Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffreplaceTb4b4b4(Ta5d6ff"Ta5d6ff_Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff Ta5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffget_doc_contentTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pathTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Tff7b72selfTff7b72.Td2a8ff_is_safe_doc_pathTb4b4b4(Te6edf3pathTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None
Tff7b72tryTb4b4b4:
Te6edf3full_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrealpathTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4, Te6edf3pathTb4b4b4)Tb4b4b4)
Te6edf3base Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrealpathTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)
Tff7b72except Tb4b4b4(Tf85149ValueErrorTb4b4b4, Tf85149OSErrorTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None
Tff7b72if Tff7b72not Te6edf3full_pathTff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3base Tff7b72+ Te6edf3osTff7b72.Td2a8ffsepTb4b4b4) Tff7b72and Te6edf3full_path Tff7b72!= Te6edf3baseTb4b4b4:
Tff7b72return Tff7b72None
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3full_pathTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None

Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3full_pathTb4b4b4, Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4, Te6edf3errorsTff7b72=Ta5d6ff"Ta5d6ffignoreTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3content Tff7b72= Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149OSError Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to read MeshChatX doc Tffd700{Te6edf3pathTffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72None

Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3pathTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.mdTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffcontentTa5d6ff"Tb4b4b4: Te6edf3contentTb4b4b4,
Ta5d6ff"Ta5d6ffhtmlTa5d6ff"Tb4b4b4: Te6edf3MarkdownRendererTff7b72.Td2a8ffrenderTb4b4b4(Te6edf3contentTb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmarkdownTa5d6ff"Tb4b4b4,
Tb4b4b4}
Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffcontentTa5d6ff"Tb4b4b4: Te6edf3contentTb4b4b4,
Ta5d6ff"Ta5d6ffhtmlTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ff<pre class=Ta5d6ff'Ta5d6ffwhitespace-pre-wrap font-monoTa5d6ff'Ta5d6ff>Tffd700{Te6edf3htmlTff7b72.Td2a8ffescapeTb4b4b4(Te6edf3contentTb4b4b4)Tffd700}Ta5d6ff</pre>Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fftextTa5d6ff"Tb4b4b4,
Tb4b4b4}
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to render MeshChatX doc Tffd700{Te6edf3pathTffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72None

Tff7b72def Td2a8ffexport_docsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""Build a ZIP archive containing the active Reticulum docs and MeshChatX docs."""
Te6edf3buffer Tff7b72= Te6edf3ioTff7b72.Td2a8ffBytesIOTb4b4b4(Tb4b4b4)
Te6edf3active_docs_dir Tff7b72= Tff7b72selfTff7b72.Td2a8ff_active_reticulum_docs_dirTb4b4b4(Tb4b4b4)
Tff7b72with Te6edf3zipfileTff7b72.Td2a8ffZipFileTb4b4b4(Te6edf3bufferTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4, Te6edf3zipfileTff7b72.Td2a8ffZIP_DEFLATEDTb4b4b4) Tff7b72as Te6edf3zip_fileTb4b4b4:
Tff7b72if Te6edf3active_docs_dir Tff7b72and Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3active_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3rootTb4b4b4, Te6edf3_Tb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Te6edf3active_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3file Tff7b72in Te6edf3filesTb4b4b4:
Te6edf3file_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3fileTb4b4b4)
Te6edf3rel_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(
Ta5d6ff"Ta5d6ffreticulum-docsTa5d6ff"Tb4b4b4,
Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrelpathTb4b4b4(Te6edf3file_pathTb4b4b4, Te6edf3active_docs_dirTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3zip_fileTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3file_pathTb4b4b4, Te6edf3rel_pathTb4b4b4)

Tff7b72for Te6edf3rootTb4b4b4, Te6edf3_Tb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3file Tff7b72in Te6edf3filesTb4b4b4:
Te6edf3file_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3fileTb4b4b4)
Te6edf3rel_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(
Ta5d6ff"Ta5d6ffmeshchatx-docsTa5d6ff"Tb4b4b4,
Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrelpathTb4b4b4(Te6edf3file_pathTb4b4b4, Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3zip_fileTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3file_pathTb4b4b4, Te6edf3rel_pathTb4b4b4)

Te6edf3bufferTff7b72.Td2a8ffseekTb4b4b4(T79c0ff0Tb4b4b4)
Tff7b72return Te6edf3bufferTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffexport_reticulum_docsTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3root_folderTff7b72=Ta5d6ff"Ta5d6ffreticulum_manualTa5d6ff"Tb4b4b4)Tb4b4b4:
T8b949e"""Build a ZIP of the active Reticulum manual in upload-compatible form.

The archive lays out files under <root_folder>/docs/ so that another
MeshChatX instance can re-import it via the /api/v1/docs/upload
endpoint without modification. Returns None when no Reticulum docs
are currently available (neither user-uploaded nor bundled).
"""
Te6edf3active_docs_dir Tff7b72= Tff7b72selfTff7b72.Td2a8ff_active_reticulum_docs_dirTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3active_docs_dir Tff7b72or Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3active_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72None

Te6edf3safe_root Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3root_folderTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ffreticulum_manualTa5d6ff"
Tff7b72if Te6edf3safe_root Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6ff.Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff..Ta5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3safe_root Tff7b72= Ta5d6ff"Ta5d6ffreticulum_manualTa5d6ff"

Te6edf3buffer Tff7b72= Te6edf3ioTff7b72.Td2a8ffBytesIOTb4b4b4(Tb4b4b4)
Tff7b72with Te6edf3zipfileTff7b72.Td2a8ffZipFileTb4b4b4(Te6edf3bufferTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4, Te6edf3zipfileTff7b72.Td2a8ffZIP_DEFLATEDTb4b4b4) Tff7b72as Te6edf3zip_fileTb4b4b4:
Tff7b72for Te6edf3rootTb4b4b4, Te6edf3_Tb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Te6edf3active_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3file Tff7b72in Te6edf3filesTb4b4b4:
Te6edf3file_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3fileTb4b4b4)
Te6edf3arcname Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(
Te6edf3safe_rootTb4b4b4,
Ta5d6ff"Ta5d6ffdocsTa5d6ff"Tb4b4b4,
Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrelpathTb4b4b4(Te6edf3file_pathTb4b4b4, Te6edf3active_docs_dirTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3zip_fileTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3file_pathTb4b4b4, Te6edf3arcnameTb4b4b4)
Te6edf3bufferTff7b72.Td2a8ffseekTb4b4b4(T79c0ff0Tb4b4b4)
Tff7b72return Te6edf3bufferTff7b72.Td2a8ffgetvalueTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffsearchTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3queryTb4b4b4, Te6edf3langTff7b72=Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3queryTb4b4b4:
Tff7b72return Tb4b4b4[Tb4b4b4]

Te6edf3results Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3query Tff7b72= Te6edf3queryTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)

Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3rootTb4b4b4, Te6edf3_Tb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3file Tff7b72in Te6edf3filesTb4b4b4:
Tff7b72if Tff7b72not Te6edf3fileTff7b72.Td2a8ffendswithTb4b4b4(Te6edf3DOC_FILE_SUFFIXESTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3file_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3fileTb4b4b4)
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(
Te6edf3file_pathTb4b4b4,
Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4,
Te6edf3errorsTff7b72=Ta5d6ff"Ta5d6ffignoreTa5d6ff"Tb4b4b4,
Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3content Tff7b72= Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3query Tff7b72in Te6edf3contentTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3idx Tff7b72= Te6edf3contentTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fffindTb4b4b4(Te6edf3queryTb4b4b4)
Te6edf3start Tff7b72= Tffa657maxTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3idx Tff7b72- T79c0ff80Tb4b4b4)
Te6edf3end Tff7b72= Tffa657minTb4b4b4(Tffa657lenTb4b4b4(Te6edf3contentTb4b4b4)Tb4b4b4, Te6edf3idx Tff7b72+ Tffa657lenTb4b4b4(Te6edf3queryTb4b4b4) Tff7b72+ T79c0ff120Tb4b4b4)
Te6edf3snippet Tff7b72= Te6edf3contentTb4b4b4[Te6edf3startTb4b4b4:Te6edf3endTb4b4b4]
Tff7b72if Te6edf3start Tff7b72> T79c0ff0Tb4b4b4:
Te6edf3snippet Tff7b72= Ta5d6ff"Ta5d6ff...Ta5d6ff" Tff7b72+ Te6edf3snippet
Tff7b72if Te6edf3end Tff7b72< Tffa657lenTb4b4b4(Te6edf3contentTb4b4b4)Tb4b4b4:
Te6edf3snippet Tff7b72= Te6edf3snippet Tff7b72+ Ta5d6ff"Ta5d6ff...Ta5d6ff"

Te6edf3resultsTff7b72.Td2a8ffappendTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4: Te6edf3fileTb4b4b4,
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ff/meshchatx-docs/Tffd700{Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrelpathTb4b4b4(Te6edf3file_pathTb4b4b4, Tff7b72selfTff7b72.Td2a8ffmeshchatx_docs_dirTb4b4b4)Tff7b72.Td2a8ffreplaceTb4b4b4(Te6edf3osTff7b72.Td2a8ffsepTb4b4b4, Ta5d6ff'Ta5d6ff/Ta5d6ff'Tb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffsnippetTa5d6ff"Tb4b4b4: Te6edf3snippetTb4b4b4,
Ta5d6ff"Ta5d6ffsourceTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMeshChatXTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffError searching MeshChatX doc Tffd700{Te6edf3fileTffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)

Te6edf3active_docs_dir Tff7b72= Tff7b72selfTff7b72.Td2a8ff_active_reticulum_docs_dirTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3active_docs_dir Tff7b72and Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3active_docs_dirTb4b4b4)Tb4b4b4:
Te6edf3known_langs Tff7b72= Tb4b4b4[Ta5d6ff"Ta5d6ffdeTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffesTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffjpTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffnlTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffplTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffpt-brTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fftrTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffukTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffzh-cnTa5d6ff"Tb4b4b4]

Te6edf3target_files Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72tryTb4b4b4:
Tff7b72for Te6edf3rootTb4b4b4, Te6edf3_Tb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Te6edf3active_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3file Tff7b72in Te6edf3filesTb4b4b4:
Tff7b72if Te6edf3fileTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.htmlTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3lang Tff7b72!= Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4:
Tff7b72if Ta5d6fffTa5d6ff"Ta5d6ff_Tffd700{Te6edf3langTffd700}Ta5d6ff.htmlTa5d6ff" Tff7b72in Te6edf3fileTb4b4b4:
Te6edf3target_filesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3fileTb4b4b4)Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3has_lang_suffix Tff7b72= Tff7b72False
Tff7b72for Te6edf3lang_code Tff7b72in Te6edf3known_langsTb4b4b4:
Tff7b72if Ta5d6fffTa5d6ff"Ta5d6ff_Tffd700{Te6edf3lang_codeTffd700}Ta5d6ff.htmlTa5d6ff" Tff7b72in Te6edf3fileTb4b4b4:
Te6edf3has_lang_suffix Tff7b72= Tff7b72True
Tff7b72break
Tff7b72if Tff7b72not Te6edf3has_lang_suffixTb4b4b4:
Te6edf3target_filesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3fileTb4b4b4)Tb4b4b4)

Tff7b72if Tff7b72not Te6edf3target_files Tff7b72and Te6edf3lang Tff7b72!= Ta5d6ff"Ta5d6ffenTa5d6ff"Tb4b4b4:
Tff7b72for Te6edf3rootTb4b4b4, Te6edf3_Tb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Te6edf3active_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3file Tff7b72in Te6edf3filesTb4b4b4:
Tff7b72if Te6edf3fileTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff.htmlTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3has_lang_suffix Tff7b72= Tff7b72False
Tff7b72for Te6edf3lang_code Tff7b72in Te6edf3known_langsTb4b4b4:
Tff7b72if Ta5d6fffTa5d6ff"Ta5d6ff_Tffd700{Te6edf3lang_codeTffd700}Ta5d6ff.htmlTa5d6ff" Tff7b72in Te6edf3fileTb4b4b4:
Te6edf3has_lang_suffix Tff7b72= Tff7b72True
Tff7b72break
Tff7b72if Tff7b72not Te6edf3has_lang_suffixTb4b4b4:
Te6edf3target_filesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3fileTb4b4b4)Tb4b4b4)

Tff7b72for Te6edf3file_path Tff7b72in Te6edf3target_filesTb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3file_pathTb4b4b4, Te6edf3encodingTff7b72=Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4, Te6edf3errorsTff7b72=Ta5d6ff"Ta5d6ffignoreTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3content Tff7b72= Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)

Te6edf3text_content Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff<[^>]+>Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff Ta5d6ff"Tb4b4b4, Te6edf3contentTb4b4b4)
Te6edf3text_content Tff7b72= Ta5d6ff"Ta5d6ff Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3text_contentTff7b72.Td2a8ffsplitTb4b4b4(Tb4b4b4)Tb4b4b4)

Tff7b72if Te6edf3query Tff7b72in Te6edf3text_contentTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3title_match Tff7b72= Te6edf3reTff7b72.Td2a8ffsearchTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6ff<title>(.*?)</title>Ta5d6ff"Tb4b4b4,
Te6edf3contentTb4b4b4,
Te6edf3reTff7b72.Td2a8ffIGNORECASE Tff7b72| Te6edf3reTff7b72.Td2a8ffDOTALLTb4b4b4,
Tb4b4b4)
Te6edf3title Tff7b72= Tb4b4b4(
Te6edf3title_matchTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3title_match
Tff7b72else Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3file_pathTb4b4b4)
Tb4b4b4)
Te6edf3title Tff7b72= Te6edf3reTff7b72.Td2a8ffsubTb4b4b4(Ta5d6ffrTa5d6ff"Ta5d6ff\Ta5d6ffs+[Ta5d6ff\Ta5d6ffu2014-].*$Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3titleTb4b4b4)

Te6edf3idx Tff7b72= Te6edf3text_contentTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fffindTb4b4b4(Te6edf3queryTb4b4b4)
Te6edf3start Tff7b72= Tffa657maxTb4b4b4(T79c0ff0Tb4b4b4, Te6edf3idx Tff7b72- T79c0ff80Tb4b4b4)
Te6edf3end Tff7b72= Tffa657minTb4b4b4(Tffa657lenTb4b4b4(Te6edf3text_contentTb4b4b4)Tb4b4b4, Te6edf3idx Tff7b72+ Tffa657lenTb4b4b4(Te6edf3queryTb4b4b4) Tff7b72+ T79c0ff120Tb4b4b4)
Te6edf3snippet Tff7b72= Te6edf3text_contentTb4b4b4[Te6edf3startTb4b4b4:Te6edf3endTb4b4b4]
Tff7b72if Te6edf3start Tff7b72> T79c0ff0Tb4b4b4:
Te6edf3snippet Tff7b72= Ta5d6ff"Ta5d6ff...Ta5d6ff" Tff7b72+ Te6edf3snippet
Tff7b72if Te6edf3end Tff7b72< Tffa657lenTb4b4b4(Te6edf3text_contentTb4b4b4)Tb4b4b4:
Te6edf3snippet Tff7b72= Te6edf3snippet Tff7b72+ Ta5d6ff"Ta5d6ff...Ta5d6ff"

Te6edf3rel_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrelpathTb4b4b4(Te6edf3file_pathTb4b4b4, Te6edf3active_docs_dirTb4b4b4)
Te6edf3resultsTff7b72.Td2a8ffappendTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4: Te6edf3titleTb4b4b4,
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ff/reticulum-docs/Tffd700{Te6edf3rel_pathTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffsnippetTa5d6ff"Tb4b4b4: Te6edf3snippetTb4b4b4,
Ta5d6ff"Ta5d6ffsourceTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffReticulumTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tff7b72if Tffa657lenTb4b4b4(Te6edf3resultsTb4b4b4) Tff7b72>Tff7b72= T79c0ff25Tb4b4b4:
Tff7b72break
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffError searching file Tffd700{Te6edf3file_pathTffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffSearch failed: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)

Tff7b72return Te6edf3results

Tff7b72def Td2a8ffhas_docsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
T8b949e"""True if either user-uploaded or bundled Reticulum docs are available."""
Tff7b72return Tff7b72selfTff7b72.Td2a8ffhas_user_docsTb4b4b4(Tb4b4b4) Tff7b72or Tff7b72selfTff7b72.Td2a8ffhas_bundled_docsTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffhas_user_docsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4, Ta5d6ff"Ta5d6ffindex.htmlTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72True
Tff7b72return Tffa657lenTb4b4b4(Tff7b72selfTff7b72.Td2a8ffget_available_versionsTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72> T79c0ff0

Tff7b72def Td2a8ffhas_bundled_docsTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffbundled_docs_dirTb4b4b4, Ta5d6ff"Ta5d6ffindex.htmlTa5d6ff"Tb4b4b4)Tb4b4b4)

Tff7b72def Td2a8fffind_docs_fileTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3rel_pathTb4b4b4)Tb4b4b4:
T8b949e"""Resolve rel_path against user docs first, then bundled docs.

Returns the absolute on-disk path of the matching file, or None when
the path either escapes the docs roots or no file exists in either
location. Path traversal attempts are rejected.
"""
Tff7b72if Te6edf3rel_path Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3rel_path Tff7b72= Ta5d6ff"Ta5d6ff"
Tff7b72for Te6edf3base Tff7b72in Tb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4, Tff7b72selfTff7b72.Td2a8ffbundled_docs_dirTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3base Tff7b72or Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3baseTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72tryTb4b4b4:
Te6edf3candidate Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrealpathTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3baseTb4b4b4, Te6edf3rel_pathTb4b4b4)Tb4b4b4)
Te6edf3base_real Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrealpathTb4b4b4(Te6edf3baseTb4b4b4)
Tff7b72except Tb4b4b4(Tf85149ValueErrorTb4b4b4, Tf85149OSErrorTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Te6edf3candidate Tff7b72!= Te6edf3base_real Tff7b72and Tff7b72not Te6edf3candidateTff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3base_real Tff7b72+ Te6edf3osTff7b72.Td2a8ffsepTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3candidateTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3candidate
Tff7b72return Tff7b72None

Tff7b72def Td2a8ff_active_reticulum_docs_dirTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_dirTb4b4b4, Ta5d6ff"Ta5d6ffindex.htmlTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ffdocs_dir
Tff7b72if Tff7b72selfTff7b72.Td2a8ffhas_bundled_docsTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Tff7b72selfTff7b72.Td2a8ffbundled_docs_dir
Tff7b72return Tff7b72None

Tff7b72def Td2a8ffupload_zipTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3zip_bytesTb4b4b4, Te6edf3versionTb4b4b4)Tb4b4b4:
T8b949e"""Extract a user-uploaded docs ZIP into a new version and switch to it."""
Tff7b72selfTff7b72.Td2a8ffupload_status Tff7b72= Ta5d6ff"Ta5d6ffextractingTa5d6ff"
Tff7b72selfTff7b72.Td2a8ffupload_progress Tff7b72= T79c0ff0
Tff7b72selfTff7b72.Td2a8fflast_error Tff7b72= Tff7b72None

Tff7b72tryTb4b4b4:
Te6edf3zip_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_base_dirTb4b4b4, Ta5d6ff"Ta5d6ffuploaded.zipTa5d6ff"Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3zip_pathTb4b4b4, Ta5d6ff"Ta5d6ffwbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3zip_bytesTb4b4b4)

Tff7b72selfTff7b72.Td2a8ff_extract_docsTb4b4b4(Te6edf3zip_pathTb4b4b4, Te6edf3versionTb4b4b4)

Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3zip_pathTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3zip_pathTb4b4b4)

Tff7b72selfTff7b72.Td2a8ffupload_status Tff7b72= Ta5d6ff"Ta5d6ffcompletedTa5d6ff"
Tff7b72selfTff7b72.Td2a8ffupload_progress Tff7b72= T79c0ff100
Tff7b72selfTff7b72.Td2a8ffswitch_versionTb4b4b4(Te6edf3versionTb4b4b4)
Tff7b72return Tff7b72True
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72selfTff7b72.Td2a8fflast_error Tff7b72= Tffa657strTb4b4b4(Te6edf3eTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffupload_status Tff7b72= Ta5d6ff"Ta5d6fferrorTa5d6ff"
Te6edf3loggingTff7b72.Td2a8ffexceptionTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to upload docs: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72False

Tff7b72def Td2a8ff_extract_docsTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3zip_pathTb4b4b4, Te6edf3versionTb4b4b4)Tb4b4b4:
Te6edf3safe_version Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffbasenameTb4b4b4(Te6edf3versionTb4b4b4)
Tff7b72if Tff7b72not Te6edf3safe_version Tff7b72or Te6edf3safe_version Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6ff.Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff..Ta5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffInvalid version name: Tffd700{Te6edf3versionTffd700}Ta5d6ff"Tb4b4b4)

Te6edf3version_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4, Te6edf3safe_versionTb4b4b4)
Te6edf3resolved Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrealpathTb4b4b4(Te6edf3version_dirTb4b4b4)
Te6edf3base Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrealpathTb4b4b4(Tff7b72selfTff7b72.Td2a8ffversions_dirTb4b4b4)
Tff7b72if Tff7b72not Te6edf3resolvedTff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3base Tff7b72+ Te6edf3osTff7b72.Td2a8ffsepTb4b4b4)Tb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffInvalid version name: Tffd700{Te6edf3versionTffd700}Ta5d6ff"Tb4b4b4)

Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3version_dirTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_remove_tree_force_writableTb4b4b4(Te6edf3version_dirTb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3version_dirTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ensure_dir_writableTb4b4b4(Te6edf3version_dirTb4b4b4)

Te6edf3temp_extract Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffdocs_base_dirTb4b4b4, Ta5d6ff"Ta5d6fftemp_extractTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3temp_extractTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_remove_tree_force_writableTb4b4b4(Te6edf3temp_extractTb4b4b4)

Tff7b72with Te6edf3zipfileTff7b72.Td2a8ffZipFileTb4b4b4(Te6edf3zip_pathTb4b4b4, Ta5d6ff"Ta5d6ffrTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3zip_refTb4b4b4:
Te6edf3namelist Tff7b72= Te6edf3zip_refTff7b72.Td2a8ffnamelistTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3namelistTb4b4b4:
Tff7b72raise Tf85149ExceptionTb4b4b4(Ta5d6ff"Ta5d6ffZip file is emptyTa5d6ff"Tb4b4b4)

Te6edf3root_folder Tff7b72= Te6edf3namelistTb4b4b4[T79c0ff0Tb4b4b4]Tff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4]

Te6edf3docs_prefix Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3root_folderTffd700}Ta5d6ff/docs/Ta5d6ff"
Te6edf3has_docs_subfolder Tff7b72= Tffa657anyTb4b4b4(Te6edf3mTff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3docs_prefixTb4b4b4) Tff7b72for Te6edf3m Tff7b72in Te6edf3namelistTb4b4b4)

Tff7b72if Te6edf3has_docs_subfolderTb4b4b4:
Te6edf3members_to_extract Tff7b72= Tb4b4b4[Te6edf3m Tff7b72for Te6edf3m Tff7b72in Te6edf3namelist Tff7b72if Te6edf3mTff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3docs_prefixTb4b4b4)Tb4b4b4]
Tff7b72for Te6edf3member Tff7b72in Te6edf3members_to_extractTb4b4b4:
Tff7b72if Ta5d6ff"Ta5d6ff..Ta5d6ff" Tff7b72in Te6edf3memberTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3zip_refTff7b72.Td2a8ffextractTb4b4b4(Te6edf3memberTb4b4b4, Te6edf3temp_extractTb4b4b4)

Te6edf3src_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3temp_extractTb4b4b4, Te6edf3root_folderTb4b4b4, Ta5d6ff"Ta5d6ffdocsTa5d6ff"Tb4b4b4)
Tff7b72for Te6edf3item Tff7b72in Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Te6edf3src_pathTb4b4b4)Tb4b4b4:
Te6edf3s Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3src_pathTb4b4b4, Te6edf3itemTb4b4b4)
Te6edf3d Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3version_dirTb4b4b4, Te6edf3itemTb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3sTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_copy_tree_no_metadataTb4b4b4(Te6edf3sTb4b4b4, Te6edf3dTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_copy_file_no_metadataTb4b4b4(Te6edf3sTb4b4b4, Te6edf3dTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3safe_members Tff7b72= Tb4b4b4[Te6edf3m Tff7b72for Te6edf3m Tff7b72in Te6edf3namelist Tff7b72if Ta5d6ff"Ta5d6ff..Ta5d6ff" Tff7b72not Tff7b72in Te6edf3mTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tb4b4b4]
Te6edf3zip_refTff7b72.Td2a8ffextractallTb4b4b4(Te6edf3temp_extractTb4b4b4, Te6edf3membersTff7b72=Te6edf3safe_membersTb4b4b4)
Te6edf3src_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3temp_extractTb4b4b4, Te6edf3root_folderTb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3src_pathTb4b4b4) Tff7b72and Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3src_pathTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3item Tff7b72in Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Te6edf3src_pathTb4b4b4)Tb4b4b4:
Te6edf3s Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3src_pathTb4b4b4, Te6edf3itemTb4b4b4)
Te6edf3d Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3version_dirTb4b4b4, Te6edf3itemTb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3sTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_copy_tree_no_metadataTb4b4b4(Te6edf3sTb4b4b4, Te6edf3dTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_copy_file_no_metadataTb4b4b4(Te6edf3sTb4b4b4, Te6edf3dTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72for Te6edf3item Tff7b72in Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Te6edf3temp_extractTb4b4b4)Tb4b4b4:
Te6edf3s Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3temp_extractTb4b4b4, Te6edf3itemTb4b4b4)
Te6edf3d Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3version_dirTb4b4b4, Te6edf3itemTb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3sTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_copy_tree_no_metadataTb4b4b4(Te6edf3sTb4b4b4, Te6edf3dTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_copy_file_no_metadataTb4b4b4(Te6edf3sTb4b4b4, Te6edf3dTb4b4b4)

Tff7b72with Tffa657openTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3version_dirTb4b4b4, Ta5d6ff"Ta5d6ff.versionTa5d6ff"Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3versionTb4b4b4)

Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3temp_extractTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_remove_tree_force_writableTb4b4b4(Te6edf3temp_extractTb4b4b4)

Tff7b72def Td2a8ff_ensure_dir_writableTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pathTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3pathTb4b4b4)Tb4b4b4:
Tff7b72return
Tff7b72tryTb4b4b4:
Te6edf3osTff7b72.Td2a8ffchmodTb4b4b4(Te6edf3pathTb4b4b4, T79c0ff0o755Tb4b4b4) T8b949e# noqa: S103
Tff7b72except Tf85149OSErrorTb4b4b4:
Tff7b72pass

Tff7b72def Td2a8ff_remove_tree_force_writableTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pathTb4b4b4)Tb4b4b4:
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3pathTb4b4b4)Tb4b4b4:
Tff7b72return
Tff7b72for Te6edf3rootTb4b4b4, Te6edf3dirsTb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Te6edf3pathTb4b4b4, Te6edf3topdownTff7b72=Tff7b72FalseTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3name Tff7b72in Te6edf3filesTb4b4b4:
Te6edf3file_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3nameTb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3osTff7b72.Td2a8ffchmodTb4b4b4(Te6edf3file_pathTb4b4b4, T79c0ff0o644Tb4b4b4)
Tff7b72except Tf85149OSErrorTb4b4b4:
Tff7b72pass
Tff7b72for Te6edf3name Tff7b72in Te6edf3dirsTb4b4b4:
Te6edf3dir_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3nameTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ensure_dir_writableTb4b4b4(Te6edf3dir_pathTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ensure_dir_writableTb4b4b4(Te6edf3pathTb4b4b4)
Te6edf3shutilTff7b72.Td2a8ffrmtreeTb4b4b4(Te6edf3pathTb4b4b4)

Tff7b72def Td2a8ff_copy_file_no_metadataTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3srcTb4b4b4, Te6edf3dstTb4b4b4)Tb4b4b4:
Te6edf3parent Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffdirnameTb4b4b4(Te6edf3dstTb4b4b4)
Tff7b72if Te6edf3parentTb4b4b4:
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3parentTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ensure_dir_writableTb4b4b4(Te6edf3parentTb4b4b4)
Te6edf3shutilTff7b72.Td2a8ffcopyfileTb4b4b4(Te6edf3srcTb4b4b4, Te6edf3dstTb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3osTff7b72.Td2a8ffchmodTb4b4b4(Te6edf3dstTb4b4b4, T79c0ff0o644Tb4b4b4)
Tff7b72except Tf85149OSErrorTb4b4b4:
Tff7b72pass

Tff7b72def Td2a8ff_copy_tree_no_metadataTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3srcTb4b4b4, Te6edf3dstTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3dstTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ensure_dir_writableTb4b4b4(Te6edf3dstTb4b4b4)
Tff7b72for Te6edf3rootTb4b4b4, Te6edf3dirsTb4b4b4, Te6edf3files Tff7b72in Te6edf3osTff7b72.Td2a8ffwalkTb4b4b4(Te6edf3srcTb4b4b4)Tb4b4b4:
Te6edf3rel_root Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffrelpathTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3srcTb4b4b4)
Te6edf3target_root Tff7b72= Te6edf3dst Tff7b72if Te6edf3rel_root Tff7b72== Ta5d6ff"Ta5d6ff.Ta5d6ff" Tff7b72else Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3dstTb4b4b4, Te6edf3rel_rootTb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3target_rootTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ensure_dir_writableTb4b4b4(Te6edf3target_rootTb4b4b4)
Tff7b72for Te6edf3dirname Tff7b72in Te6edf3dirsTb4b4b4:
Te6edf3target_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3target_rootTb4b4b4, Te6edf3dirnameTb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3target_dirTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72selfTff7b72.Td2a8ff_ensure_dir_writableTb4b4b4(Te6edf3target_dirTb4b4b4)
Tff7b72for Te6edf3filename Tff7b72in Te6edf3filesTb4b4b4:
Tff7b72selfTff7b72.Td2a8ff_copy_file_no_metadataTb4b4b4(
Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3rootTb4b4b4, Te6edf3filenameTb4b4b4)Tb4b4b4,
Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3target_rootTb4b4b4, Te6edf3filenameTb4b4b4)Tb4b4b4,
Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────